package com.atguigu.dga.assess.assessor.storage;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.dga.assess.assessor.AssessorTemplate;
import com.atguigu.dga.assess.bean.AssessParam;
import com.atguigu.dga.assess.bean.GovernanceAssessDetail;
import com.atguigu.dga.assess.bean.MyFileld;
import com.atguigu.dga.meta.bean.TableMetaInfo;
import com.atguigu.dga.util.CacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by Smexy on 2023/10/30

 同层次两个表字段重复(字段名+注释)超过{percent}%，则给0分，其余给10分
 */
@Component("TABLE_SIMILAR")
public class CheckSimiliarTable extends AssessorTemplate
{
    @Autowired
    private CacheUtil cacheUtil;
    @Override
    protected void assess(AssessParam param, GovernanceAssessDetail detail) {

        TableMetaInfo metaInfo = param.getMetaInfo();
        //获取当前表的分层
        String dwLevel = metaInfo.getTableMetaInfoExtra().getDwLevel();
        //获取到当前表所对应的key
        String key = cacheUtil.getKey(metaInfo);
        //获取当前表的所有的字段集合(每一个字段的 字段名+注释)
        String colNameJson = metaInfo.getColNameJson();
        Set<String> currentTableColSet = getColNameAndCommentSet(colNameJson);
        //获取阈值percent
        Integer limtPercent = getIntegerValueFromConfig(param,"percent");
        /*
            要同一层次的每一张表进行比对，查看是否有相似的部分
                需要先查询同一层次的每一张表的元数据信息.
                在当前考评器中，执行查询，效率低，要在每一张表考评时都需要去查询，共查询 79次。
                实际上，可以把这些元数据信息，一次性查询好，放入到程序的缓存中，在考评时只需要读取缓存即可，而没有必要查询数据库！
         */
        // query();
        //过滤出要比对的表的元数据集合
        Set<TableMetaInfo> comparedTableMetaInfos = cacheUtil.getTableMetaInfoMap()
                                              .entrySet()
                                              .stream()
                                              .filter(entry ->
                                                  dwLevel.equals(entry.getValue().getTableMetaInfoExtra().getDwLevel()) //留下同一层级
                                                      &&
                                                      !key.equals(entry.getKey()) //把自己排除
                                              )
                                              .map(entry -> entry.getValue())
                                              .collect(Collectors.toSet());

        //准备一个收集比对结果的集合
        List<JSONObject> result = new ArrayList<>();
        //进行比对
        for (TableMetaInfo comparedTableMetaInfo : comparedTableMetaInfos) {
            //获取要比对的这张表的 列的set集合
            Set<String> comparedTableColSet = getColNameAndCommentSet(comparedTableMetaInfo.getColNameJson());
            //进行交集运算   把当前表的set集合放后面，因为后续还要循环使用
            boolean ifInter = comparedTableColSet.retainAll(currentTableColSet);
            if (ifInter){
                BigDecimal percent = BigDecimal.valueOf(comparedTableColSet.size())
                                               .divide(BigDecimal.valueOf(currentTableColSet.size()),2, RoundingMode.HALF_UP)
                                                  .movePointRight(2);
                //计算比例,如果超过阈值
                if (percent.compareTo(BigDecimal.valueOf(limtPercent)) == 1){
                    //记录，返回结果
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("重复百比例",percent);
                    jsonObject.put("重复的表", cacheUtil.getKey(comparedTableMetaInfo));
                    jsonObject.put("重复的字段",comparedTableColSet);
                    result.add(jsonObject);
                }
            }
        }

        //判断是否有重复的，打分
        if (!result.isEmpty()){
            assessScore(BigDecimal.ZERO,"和其他表字段重复，过分相似",JSON.toJSONString(result),detail,false,null);
        }
    }



    /**
     *
     * @param colNameJson  格式是:[]
     * @return  [ 字段1名_注释,字段2名_注释  ]
     */
    private Set<String> getColNameAndCommentSet(String colNameJson){
        List<MyFileld> myFilelds = JSON.parseArray(colNameJson, MyFileld.class);
        Set<String> set = myFilelds
            .stream()
            .map(f -> f.getName().concat("_").concat(f.getComment() == null ? "无" : f.getComment() ))
            .collect(Collectors.toSet());
        return set;
    }
}
